/**
 **************************************************************************************************************************
 * 
 **************************************************************************************************************************
 * @file RBEffect.h
 **************************************************************************************************************************/

#pragma once

#ifdef  HEADER_MSG
#pragma HEADER_MSG(RBEffect.h)
#endif


/**************************************************************************************************************************
 * Includes
 **************************************************************************************************************************/
#include "RBMain/RBCommon.h"
#include <hash_map>
#include <stb.h>

#include "RBRenderProcess/RBEffectVariable.h"

/**************************************************************************************************************************
 * Forward declarations
 **************************************************************************************************************************/
class RBEffectTechnique;
class RBGeometry;
class RBMaterial;
class RBTextureSampler;
class RBRenderer;
class RBEffectFactory;

struct RBShaderConstantBufferVariable;
struct RBShaderResourceViewVariable;
struct RBShaderSamplerVariable;

class RBShaderResourceView;
class RBShaderSamplerState;

class RBBlendState;
class RBDepthStencilState;
class RBRasterizerState;

/**************************************************************************************************************************
 * Classes
 **************************************************************************************************************************/
#ifdef __cplusplus
#define STB_EXTERN   extern "C"
#else
#define STB_EXTERN   extern
#endif

stb_declare_hash(STB_EXTERN, stb_i32_dict, stb_i32_dict_, stb_int32, void*);
stb_declare_hash(STB_EXTERN, stb_i64_dict, stb_i64_dict_, stb_int64, void*);

class RBEffect
{
    friend class RBEffectCompiler;
public:
    
                       ~RBEffect            ();

    static void         Init                ();

    RBEffectTechnique*  GetTechnique        (uint32 uiTechnique);
    uint32              GetTechniqueByName  (const RBString& strName);
    uint32              GetTechniqueCount   () const { return m_vTechniques.size(); }

    void                AddTechnique        (const RBString& strName, RBEffectTechnique* pTechnique);
    void                DestroyTechniques   ();

    void                BuildEffectBuffer   (RBRenderer* pRenderer, const RBGeometry* pGeometry, const RBMaterial* pMaterial, 
                                             void* pBufferData, const RBShaderResourceView** ppViews, const RBShaderSamplerState** ppSamplers,
                                             const RBEffectFactory* pEffectFactory) const;

    static uint32       GetSemantic         (const RBString& strName);
    static uint32       get_semantic_from_name(const RBString& strName);
    static uint32       GetType             (const RBString& strType);

    void                SetEffectVariables  (const std::vector<RBEffectCBVariable>& vEffectCBVariables, 
                                             const std::vector<RBEffectRVVariable>& vEffectRVVariables,
                                             const std::vector<RBEffectSamplerVariable>& vEffectSamplersVariables
                                             );

    static RBShaderSamplerState* FindSamplerState  (const RBTextureSampler& sampler);
    static RBRasterizerState*    FindRasterState   (const RBMaterial& material);
    static RBBlendState*         FindBlendState    (const RBMaterial& material, uint32 colorWrites);
    static RBDepthStencilState*  FindDepthStencilState  (const RBMaterial& material);

public:
    RBString            Name;
    RBString            Filename;

private:
    typedef uint32 SamplerStateKey;
    typedef uint32 RasterStateKey;
    typedef uint64 BlendStateKey;
    typedef uint64 DepthStencilStateKey;
    typedef stdext::hash_map<SamplerStateKey, RBShaderSamplerState*> RBShaderSamplerStateMap;
    typedef stdext::hash_map<RasterStateKey, RBRasterizerState*> RBRasterizerStateMap;
    typedef stdext::hash_map<BlendStateKey, RBBlendState*> RBBlendStateMap;
    typedef stdext::hash_map<DepthStencilStateKey, RBDepthStencilState*> RBDepthStencilStateMap;

    static SamplerStateKey       CreateSamplerKey  (const RBTextureSampler& sampler);
    static RasterStateKey        CreateRasterKey   (const RBMaterial& material);
    static BlendStateKey         CreateBlendKey    (const RBMaterial& material, uint32 colorWrites);
    static DepthStencilStateKey  CreateDepthStencilKey(const RBMaterial& material);

private:

    std::vector<RBEffectTechnique*> m_vTechniques;
    std::vector<RBString> m_vTechniqueNames;
    std::vector<RBEffectCBVariable> m_vEffectCBVariables;
    std::vector<RBEffectRVVariable> m_vEffectRVVariables;
    std::vector<RBEffectSamplerVariable> m_vEffectSamplerVariables;


    static stdext::hash_map<RBString, uint32> ms_mSemantics;
    static stdext::hash_map<RBString, uint32> ms_mTypes;

    struct rb_state_cache
    {
        rb_state_cache();
        ~rb_state_cache();
        stb_i32_dict* sampler_states;
        stb_i32_dict* raster_states;
        stb_i64_dict* blend_states;
        stb_i64_dict* depth_stencil_states;
    };

    static rb_state_cache ms_cache;

    static RBShaderSamplerStateMap ms_mSamplerStates;
    static RBRasterizerStateMap ms_mRasterStates;
    static RBBlendStateMap ms_mBlendStates;
    static RBDepthStencilStateMap ms_mDepthStencilStates;

};
